#include "idea.h"


static uint16_t multiply(const uint16_t a, const uint16_t b)
{
    // the result may exceed a 32-bit integer.
    uint64_t tmp_a, tmp_b;

    if (a != 0)
        tmp_a = a;
    else
        tmp_a = 1 << 16;

    if (b != 0)
        tmp_b = b;
    else
        tmp_b = 1 << 16;

    return (tmp_a * tmp_b) % IDEA_MULTIPLY_MODULUS;
}


static uint16_t add(const uint16_t a, const uint16_t b)
{
    uint32_t tmp = a + b;
    return tmp % IDEA_ADD_MODULUS;
}


static uint16_t xor(const uint16_t a, const uint16_t b)
{
    return a ^ b;
}


static void swap(uint16_t* const a, uint16_t* const b)
{
    uint16_t tmp = *a;
    *a = *b;
    *b = tmp;
}


void generate_subkeys(bit_array *initial_keys, uint16_t *subkeys)
{
    for (int i = 0; i < IDEA_SUBKEYS; i++) {
        if (i != 0 && i % 8 == 0) {
            bits_left_shift(initial_keys, IDEA_INITIAL_KEYS * 16, 25);
        }
        subkeys[i] = bits2hex(initial_keys, i % IDEA_INITIAL_KEYS * 16);
    }

}


void rounds(uint16_t *key, uint16_t *data)
{
    // Assert key[IDEA_ROUNDS], data[IDEA_DATA_BLOCK]

    for (int i = 0; i < IDEA_ROUNDS; i++) {
        uint16_t result1 = multiply(data[0], key[0]);
        uint16_t result2 = add(data[1], key[1]);
        uint16_t result3 = add(data[2], key[2]);
        uint16_t result4 = multiply(data[3], key[3]);
        uint16_t result5 = xor(result1, result3);
        uint16_t result6 = xor(result2, result4);
        uint16_t result7 = multiply(result5, key[4]);
        uint16_t result8 = add(result6, result7);
        uint16_t result9 = multiply(result8, key[5]);
        uint16_t result10 = add(result7, result9);

        // There is an inherent swap from one round to the next, already swapped,
        // no need to do it here - a trap for young players.

        data[0] = xor(result1, result9);
        data[1] = xor(result3, result9);
        data[2] = xor(result2, result10);
        data[3] = xor(result4, result10);

        // using key[6] through key[11] the second time,
        // ... up to key[43] through key[48] the eighth time.
        key += 6;
    }

    data[0] = multiply(data[0], key[0]);
    data[1] = add(data[1], key[2]);
    data[2] = add(data[2], key[1]);
    data[3] = multiply(data[3], key[3]);

    // The swap is not performed after round 8, UNSWAP them.
    swap(&data[1], &data[2]);
}
